package be.kuleuven.cs.mop.gui.components;


import static javax.swing.ListSelectionModel.*;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.swing.AbstractListModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;

import be.kuleuven.cs.mop.domain.model.Task;
import be.kuleuven.cs.mop.gui.dialogs.InfoDialog;
import be.kuleuven.cs.mop.util.Utils;



public class SelectionList<T> extends JList {
	private static final long serialVersionUID = 1L;
	
	private final Model<T> model;
	
	
	public SelectionList(final Collection<T> c, final boolean multiple) {
		this(new Model<T>(c));
		setSelectionMode(multiple);
	}
	private SelectionList(final Model<T> model) {
		super(model);
		this.model = model;
		
		setCellRenderer(new Renderer());
		setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		
		addMouseListener(new Listener());
	}
	
	
	
	public List<T> getSelection() {
		final List<T> list;
		synchronized (list = model.elements) {
			final int[]		indices		= getSelectedIndices();
			final List<T>	selection	= new ArrayList<T>(indices.length);
			for (final int index : indices)
				selection.add(list.get(index));
			return selection;
		}
	}
	
	@Override
	protected void processMouseEvent(final MouseEvent event) {
		super.processMouseEvent(event);
		if ((event.getID() == MouseEvent.MOUSE_PRESSED)
				&& (event.getButton() == MouseEvent.BUTTON3))
			clearSelection();
	}
	
	public void setSelection(final Collection<T> selection) {
		final List<Integer> search = new ArrayList<Integer>();
		for (final T element : selection) {
			final int index = model.elements.indexOf(element);
			if (index != -1)
				search.add(new Integer(index));
		}
		final int[] indices = new int[search.size()];
		for (int i = 0; i < indices.length; i++)
			indices[i] = search.get(i);
		setSelectedIndices(indices);
	}
	
	public void setSelectionMode(final boolean toggle) {
		setSelectionMode(toggle ?
				MULTIPLE_INTERVAL_SELECTION : SINGLE_SELECTION);
	}
	
	/**
	 * Returns a <code>JScrollPane</code> containing the <code>SelectionList</code>
	 * @param size - the preferred size for the <code>JScrollPane</code>
	 * @return
	 */
	public final JScrollPane wrap(final Dimension size) {
		return new Wrapper(size);
	}
	
	
	
	
	
	
	
	
	
	
	private final class Listener extends MouseAdapter {
		
		@Override
		public void mousePressed(final MouseEvent event) {
			if (!SelectionList.this.equals(event.getSource())
					|| (event.getButton() != MouseEvent.BUTTON3))
				return;
			
			final Object selection = getSelectedValue();
			if (selection == null) {
				return;
			} else if (selection instanceof Task) {
				new InfoDialog(null, new InfoLabel(Utils.format((Task)selection, true)));
			}
		}
		
	}
	
	
	
	
	
	@SuppressWarnings("serial")
	private static final class Model<T> extends AbstractListModel {
		
		private final List<T> elements;
		
		
		private Model(final Collection<T> c) {
			elements = new ArrayList<T>(c);
		}
		
		
		
		@Override
		public final T getElementAt(final int index) {
			return elements.get(index);
		}
		
		@Override
		public final int getSize() { return elements.size(); }
		
	}
	
	
	
	
	
	@SuppressWarnings("serial")
	private static final class Renderer extends DefaultListCellRenderer {
		
		@Override
		public Component getListCellRendererComponent(final JList list,
				final Object value, final int index,
				final boolean selected, final boolean focus) {
			super.getListCellRendererComponent(list, value, index, selected, focus);
			
			setBackground(selected ? Color.BLACK : Color.WHITE);
			setBorder(null);
			setFont(new Font(Font.MONOSPACED, Font.BOLD, 14));
			setForeground(selected ? Color.WHITE : Color.BLACK);
			
			return this;
		}
		
		@Override
		public Dimension getPreferredSize() {
			final Dimension dim = super.getPreferredSize();
			dim.height = 25;
			return dim;
		}
		
	}
	
	
	
	
	
	private final class Wrapper extends JScrollPane {
		private static final long serialVersionUID = 1L;
		
		
		private Wrapper(final Dimension dim) {
			super(SelectionList.this,
					ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
					ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
			setPreferredSize(dim);
		}
	}
	
}